home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / uemlsrc / line.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-08-24  |  17.1 KB  |  503 lines

  1. /*
  2.  * The functions in this file
  3.  * are a general set of line management
  4.  * utilities. They are the only routines that
  5.  * touch the text. They also touch the buffer
  6.  * and window structures, to make sure that the
  7.  * necessary updating gets done. There are routines
  8.  * in this file that handle the kill buffer too.
  9.  * It isn't here for any good reason.
  10.  *
  11.  * Note that this code only updates the dot and
  12.  * mark values in the window list. Since all the code
  13.  * acts on the current window, the buffer that we
  14.  * are editing must be being displayed, which means
  15.  * that "b_nwnd" is non zero, which means that the
  16.  * dot and mark values in the buffer headers are
  17.  * nonsense.
  18.  */
  19. #include        <stdio.h>
  20. #include        "ed.h"
  21.  
  22. #define NBLOCK  16                      /* Line block chunk size        */
  23. #define KBLOCK  256                     /* Kill buffer block size       */
  24.  
  25. char    *kbufp  = NULL;                 /* Kill buffer data             */
  26. int     kused   = 0;                    /* # of bytes used in KB        */
  27. int     ksize   = 0;                    /* # of bytes allocated in KB   */
  28.  
  29. /*
  30.  * This routine allocates a block
  31.  * of memory large enough to hold a LINE
  32.  * containing "used" characters. The block is
  33.  * always rounded up a bit. Return a pointer
  34.  * to the new block, or NULL if there isn't
  35.  * any memory left. Print a message in the
  36.  * message line if no space.
  37.  */
  38. LINE    *
  39. lalloc(used)
  40. register int    used;
  41. {
  42.         register LINE   *lp;
  43.         register int    size;
  44.  
  45.         size = (used+NBLOCK-1) & ~(NBLOCK-1);
  46.         if (size == 0)                          /* Assume that an empty */
  47.                 size = NBLOCK;                  /* line is for type-in. */
  48.         if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
  49.                 mlwrite("Cannot allocate %d bytes", size);
  50.                 return (NULL);
  51.         }
  52.         lp->l_size = size;
  53.         lp->l_used = used;
  54.         return (lp);
  55. }
  56.  
  57. /*
  58.  * Delete line "lp". Fix all of the
  59.  * links that might point at it (they are
  60.  * moved to offset 0 of the next line.
  61.  * Unlink the line from whatever buffer it
  62.  * might be in. Release the memory. The
  63.  * buffers are updated too; the magic conditions
  64.  * described in the above comments don't hold
  65.  * here.
  66.  */
  67. lfree(lp)
  68. register LINE   *lp;
  69. {
  70.         register BUFFER *bp;
  71.         register WINDOW *wp;
  72.  
  73.         wp = wheadp;
  74.         while (wp != NULL) {
  75.                 if (wp->w_linep == lp)
  76.                         wp->w_linep = lp->l_fp;
  77.                 if (wp->w_dotp  == lp) {
  78.                         wp->w_dotp  = lp->l_fp;
  79.                         wp->w_doto  = 0;
  80.                 }
  81.                 if (wp->w_markp == lp) {
  82.                         wp->w_markp = lp->l_fp;
  83.                         wp->w_marko = 0;
  84.                 }
  85.                 wp = wp->w_wndp;
  86.         }
  87.         bp = bheadp;
  88.         while (bp != NULL) {
  89.                 if (bp->b_nwnd == 0) {
  90.                         if (bp->b_dotp  == lp) {
  91.                                 bp->b_dotp = lp->l_fp;
  92.                                 bp->b_doto = 0;
  93.                         }
  94.                         if (bp->b_markp == lp) {
  95.                                 bp->b_markp = lp->l_fp;
  96.                                 bp->b_marko = 0;
  97.                         }
  98.                 }
  99.                 bp = bp->b_bufp;
  100.         }
  101.         lp->l_bp->l_fp = lp->l_fp;
  102.         lp->l_fp->l_bp = lp->l_bp;
  103.         free((char *) lp);
  104. }
  105.  
  106. /*
  107.  * This routine gets called when
  108.  * a character is changed in place in the
  109.  * current buffer. It updates all of the required
  110.  * flags in the buffer and window system. The flag
  111.  * used is passed as an argument; if the buffer is being
  112.  * displayed in more than 1 window we change EDIT to
  113.  * HARD. Set MODE if the mode line needs to be
  114.  * updated (the "*" has to be set).
  115.  */
  116. lchange(flag)
  117. register int    flag;
  118. {
  119.         register WINDOW *wp;
  120.  
  121.         if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
  122.                 flag = WFHARD;
  123.         if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
  124.                 flag |= WFMODE;                 /* update mode lines.   */
  125.                 curbp->b_flag |= BFCHG;
  126.         }
  127.         wp = wheadp;
  128.         while (wp != NULL) {
  129.                 if (wp->w_bufp == curbp)
  130.                         wp->w_flag |= flag;
  131.                 wp = wp->w_wndp;
  132.         }
  133. }
  134.  
  135. /*
  136.  * Insert "n" copies of the character "c"
  137.  * at the current location of dot. In the easy case
  138.  * all that happens is the text is stored in the line.
  139.  * In the hard case, the line has to be reallocated.
  140.  * When the window list is updated, take special
  141.  * care; I screwed it up once. You always update dot
  142.  * in the current window. You update mark, and a
  143.  * dot in another window, if it is greater than
  144.  * the place where you did the insert. Return TRUE
  145.  * if all is well, and FALSE on errors.
  146.  */
  147. linsert(n, c)
  148. register int n, c;
  149. {
  150.         register char   *cp1;
  151.         register char   *cp2;
  152.         register LINE   *lp1;
  153.         register LINE   *lp2;
  154.         register LINE   *lp3;
  155.         register int    doto;
  156.         register int    i;
  157.         register WINDOW *wp;
  158.  
  159.         lchange(WFEDIT);
  160.         lp1 = curwp->w_dotp;                    /* Current line         */
  161.         if (lp1 == curbp->b_linep) {            /* At the end: special  */
  162.                 if (curwp->w_doto != 0) {
  163.                         mlwrite("bug: linsert");
  164.                         return (FALSE);
  165.                 }
  166.                 if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  167.                         return (FALSE);
  168.                 lp3 = lp1->l_bp;                /* Previous line        */
  169.                 lp3->l_fp = lp2;                /* Link in              */
  170.                 lp2->l_fp = lp1;
  171.                 lp1->l_bp = lp2;
  172.                 lp2->l_bp = lp3;
  173.                 for (i=0; i<n; ++i)
  174.                         lp2->l_text[i] = c;
  175.                 curwp->w_dotp = lp2;
  176.                 curwp->w_doto = n;
  177.                 return (TRUE);
  178.         }
  179.         doto = curwp->w_doto;                   /* Save for later.      */
  180.         if (lp1->l_used+n > lp1->l_size) {      /* Hard: reallocate     */
  181.                 if ((lp2=lalloc(lp1->l_used+n)) == NULL)
  182.                         return (FALSE);
  183.                 cp1 = &lp1->l_text[0];
  184.                 cp2 = &lp2->l_text[0];
  185.                 while (cp1 != &lp1->l_text[doto])
  186.                         *cp2++ = *cp1++;
  187.                 cp2 += n;
  188.                 while (cp1 != &lp1->l_text[lp1->l_used])
  189.                         *cp2++ = *cp1++;
  190.                 lp1->l_bp->l_fp = lp2;
  191.                 lp2->l_fp = lp1->l_fp;
  192.                 lp1->l_fp->l_bp = lp2;
  193.                 lp2->l_bp = lp1->l_bp;
  194.                 free((char *) lp1);
  195.         } else {                                /* Easy: in place       */
  196.                 lp2 = lp1;                      /* Pretend new line     */
  197.                 lp2->l_used += n;
  198.                 cp2 = &lp1->l_text[lp1->l_used];
  199.                 cp1 = cp2-n;
  200.                 while (cp1 != &lp1->l_text[doto])
  201.                         *--cp2 = *--cp1;
  202.         }
  203.         for (i=0; i<n; ++i)                     /* Add the characters   */
  204.                 lp2->l_text[doto+i] = c;
  205.         wp = wheadp;                            /* Update windows       */
  206.         while (wp != NULL) {
  207.                 if (wp->w_linep == lp1)
  208.                         wp->w_linep = lp2;
  209.                 if (wp->w_dotp == lp1) {
  210.                         wp->w_dotp = lp2;
  211.                         if (wp==curwp || wp->w_doto>doto)
  212.                                 wp->w_doto += n;
  213.                 }
  214.                 if (wp->w_markp == lp1) {
  215.                         wp->w_markp = lp2;
  216.                         if (wp->w_marko > doto)
  217.                                 wp->w_marko += n;
  218.                 }
  219.                 wp = wp->w_wndp;
  220.         }
  221.         return (TRUE);
  222. }
  223.  
  224. /*
  225.  * Insert a newline into the buffer
  226.  * at the current location of dot in the current
  227.  * window. The funny ass-backwards way it does things
  228.  * is not a botch; it just makes the last line in
  229.  * the file not a special case. Return TRUE if everything
  230.  * works out and FALSE on error (memory allocation
  231.  * failure). The update of dot and mark is a bit
  232.  * easier then in the above case, because the split
  233.  * forces more updating.
  234.  */
  235. lnewline()
  236. {
  237.         register char   *cp1;
  238.         register char   *cp2;
  239.         register LINE   *lp1;
  240.         register LINE   *lp2;
  241.         register int    doto;
  242.         register WINDOW *wp;
  243.  
  244.         lchange(WFHARD);
  245.         lp1  = curwp->w_dotp;                   /* Get the address and  */
  246.         doto = curwp->w_doto;                   /* offset of "."        */
  247.         if ((lp2=lalloc(doto)) == NULL)         /* New first half line  */
  248.                 return (FALSE);
  249.         cp1 = &lp1->l_text[0];                  /* Shuffle text around  */
  250.         cp2 = &lp2->l_text[0];
  251.         while (cp1 != &lp1->l_text[doto])
  252.                 *cp2++ = *cp1++;
  253.         cp2 = &lp1->l_text[0];
  254.         while (cp1 != &lp1->l_text[lp1->l_used])
  255.                 *cp2++ = *cp1++;
  256.         lp1->l_used -= doto;
  257.         lp2->l_bp = lp1->l_bp;
  258.         lp1->l_bp = lp2;
  259.         lp2->l_bp->l_fp = lp2;
  260.         lp2->l_fp = lp1;
  261.         wp = wheadp;                            /* Windows              */
  262.         while (wp != NULL) {
  263.                 if (wp->w_linep == lp1)
  264.                         wp->w_linep = lp2;
  265.                 if (wp->w_dotp == lp1) {
  266.                         if (wp->w_doto < doto)
  267.                                 wp->w_dotp = lp2;
  268.                         else
  269.                                 wp->w_doto -= doto;
  270.                 }
  271.                 if (wp->w_markp == lp1) {
  272.                         if (wp->w_marko < doto)
  273.                                 wp->w_markp = lp2;
  274.                         else
  275.                                 wp->w_marko -= doto;
  276.                 }
  277.                 wp = wp->w_wndp;
  278.         }
  279.         return (TRUE);
  280. }
  281.  
  282. /*
  283.  * This function deletes "n" bytes,
  284.  * starting at dot. It understands how do deal
  285.  * with end of lines, etc. It returns TRUE if all
  286.  * of the characters were deleted, and FALSE if
  287.  * they were not (because dot ran into the end of
  288.  * the buffer. The "kflag" is TRUE if the text
  289.  * should be put in the kill buffer.
  290.  */
  291. ldelete(n, kflag)
  292. register int n, kflag;
  293. {
  294.         register char   *cp1;
  295.         register char   *cp2;
  296.         register LINE   *dotp;
  297.         register int    doto;
  298.         register int    chunk;
  299.         register WINDOW *wp;
  300.  
  301.         while (n != 0) {
  302.                 dotp = curwp->w_dotp;
  303.                 doto = curwp->w_doto;
  304.                 if (dotp == curbp->b_linep)     /* Hit end of buffer.   */
  305.                         return (FALSE);
  306.                 chunk = dotp->l_used-doto;      /* Size of chunk.       */
  307.                 if (chunk > n)
  308.                         chunk = n;
  309.                 if (chunk == 0) {               /* End of line, merge.  */
  310.                         lchange(WFHARD);
  311.                         if (ldelnewline() == FALSE
  312.                         || (kflag!=FALSE && kinsert('\n')==FALSE))
  313.                                 return (FALSE);
  314.                         --n;
  315.                         continue;
  316.                 }
  317.                 lchange(WFEDIT);
  318.                 cp1 = &dotp->l_text[doto];      /* Scrunch text.        */
  319.                 cp2 = cp1 + chunk;
  320.                 if (kflag != FALSE) {           /* Kill?                */
  321.                         while (cp1 != cp2) {
  322.                                 if (kinsert(*cp1) == FALSE)
  323.                                         return (FALSE);
  324.                                 ++cp1;
  325.                         }
  326.                         cp1 = &dotp->l_text[doto];
  327.                 }
  328.                 while (cp2 != &dotp->l_text[dotp->l_used])
  329.                         *cp1++ = *cp2++;
  330.                 dotp->l_used -= chunk;
  331.                 wp = wheadp;                    /* Fix windows          */
  332.                 while (wp != NULL) {
  333.                         if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  334.                                 wp->w_doto -= chunk;
  335.                                 if (wp->w_doto < doto)
  336.                                         wp->w_doto = doto;
  337.                         }
  338.                         if (wp->w_markp==dotp && wp->w_marko>=doto) {
  339.                                 wp->w_marko -= chunk;
  340.                                 if (wp->w_marko < doto)
  341.                                         wp->w_marko = doto;
  342.                         }
  343.                         wp = wp->w_wndp;
  344.                 }
  345.                 n -= chunk;
  346.         }
  347.         return (TRUE);
  348. }
  349.  
  350. /*
  351.  * Delete a newline. Join the current line
  352.  * with the next line. If the next line is the magic
  353.  * header line always return TRUE; merging the last line
  354.  * with the header line can be thought of as always being a
  355.  * successful operation, even if nothing is done, and this makes
  356.  * the kill buffer work "right". Easy cases can be done by
  357.  * shuffling data around. Hard cases require that lines be moved
  358.  * about in memory. Return FALSE on error and TRUE if all
  359.  * looks ok. Called by "ldelete" only.
  360.  */
  361. ldelnewline()
  362. {
  363.         register char   *cp1;
  364.         register char   *cp2;
  365.         register LINE   *lp1;
  366.         register LINE   *lp2;
  367.         register LINE   *lp3;
  368.         register WINDOW *wp;
  369.  
  370.         lp1 = curwp->w_dotp;
  371.         lp2 = lp1->l_fp;
  372.         if (lp2 == curbp->b_linep) {            /* At the buffer end.   */
  373.                 if (lp1->l_used == 0)           /* Blank line.          */
  374.                         lfree(lp1);
  375.                 return (TRUE);
  376.         }
  377.         if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  378.                 cp1 = &lp1->l_text[lp1->l_used];
  379.                 cp2 = &lp2->l_text[0];
  380.                 while (cp2 != &lp2->l_text[lp2->l_used])
  381.                         *cp1++ = *cp2++;
  382.                 wp = wheadp;
  383.                 while (wp != NULL) {
  384.                         if (wp->w_linep == lp2)
  385.                                 wp->w_linep = lp1;
  386.                         if (wp->w_dotp == lp2) {
  387.                                 wp->w_dotp  = lp1;
  388.                                 wp->w_doto += lp1->l_used;
  389.                         }
  390.                         if (wp->w_markp == lp2) {
  391.                                 wp->w_markp  = lp1;
  392.                                 wp->w_marko += lp1->l_used;
  393.                         }
  394.                         wp = wp->w_wndp;
  395.                 }
  396.                 lp1->l_used += lp2->l_used;
  397.                 lp1->l_fp = lp2->l_fp;
  398.                 lp2->l_fp->l_bp = lp1;
  399.                 free((char *) lp2);
  400.                 return (TRUE);
  401.         }
  402.         if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
  403.                 return (FALSE);
  404.         cp1 = &lp1->l_text[0];
  405.         cp2 = &lp3->l_text[0];
  406.         while (cp1 != &lp1->l_text[lp1->l_used])
  407.                 *cp2++ = *cp1++;
  408.         cp1 = &lp2->l_text[0];
  409.         while (cp1 != &lp2->l_text[lp2->l_used])
  410.                 *cp2++ = *cp1++;
  411.         lp1->l_bp->l_fp = lp3;
  412.         lp3->l_fp = lp2->l_fp;
  413.         lp2->l_fp->l_bp = lp3;
  414.         lp3->l_bp = lp1->l_bp;
  415.         wp = wheadp;
  416.         while (wp != NULL) {
  417.                 if (wp->w_linep==lp1 || wp->w_linep==lp2)
  418.                         wp->w_linep = lp3;
  419.                 if (wp->w_dotp == lp1)
  420.                         wp->w_dotp  = lp3;
  421.                 else if (wp->w_dotp == lp2) {
  422.                         wp->w_dotp  = lp3;
  423.                         wp->w_doto += lp1->l_used;
  424.                 }
  425.                 if (wp->w_markp == lp1)
  426.                         wp->w_markp  = lp3;
  427.                 else if (wp->w_markp == lp2) {
  428.                         wp->w_markp  = lp3;
  429.                         wp->w_marko += lp1->l_used;
  430.                 }
  431.                 wp = wp->w_wndp;
  432.         }
  433.         free((char *) lp1);
  434.         free((char *) lp2);
  435.         return (TRUE);
  436. }
  437.  
  438. /*
  439.  * Delete all of the text
  440.  * saved in the kill buffer. Called by commands
  441.  * when a new kill context is being created. The kill
  442.  * buffer array is released, just in case the buffer has
  443.  * grown to immense size. No errors.
  444.  */
  445. kdelete()
  446. {
  447.         if (kbufp != NULL) {
  448.                 free((char *) kbufp);
  449.                 kbufp = NULL;
  450.                 kused = 0;
  451.                 ksize = 0;
  452.         }
  453. }
  454.  
  455. /*
  456.  * Insert a character to the kill buffer,
  457.  * enlarging the buffer if there isn't any room. Always
  458.  * grow the buffer in chunks, on the assumption that if you
  459.  * put something in the kill buffer you are going to put
  460.  * more stuff there too later. Return TRUE if all is
  461.  * well, and FALSE on errors.
  462.  */
  463. kinsert(c)
  464. register int c;
  465. {
  466.         register char   *nbufp;
  467.         register int    i;
  468.  
  469.         if (kused == ksize) {
  470.                 if ((nbufp =  malloc(ksize+KBLOCK)) == NULL)
  471.                         return (FALSE);
  472.                 for (i=0; i<ksize; ++i)
  473.                         nbufp[i] = kbufp[i];
  474.                 if (kbufp != NULL)
  475.                         free((char *) kbufp);
  476.                 kbufp  = nbufp;
  477.                 ksize += KBLOCK;
  478.         }
  479.         kbufp[kused++] = c;
  480.         return (TRUE);
  481. }
  482.  
  483. /*
  484.  * This function gets characters from
  485.  * the kill buffer. If the character index "n" is
  486.  * off the end, it returns "-1". This lets the caller
  487.  * just scan along until it gets a "-1" back.
  488.  */
  489. kremove(n)
  490. register int n;
  491. {
  492.         if (n >= kused)
  493.                 return (-1);
  494.         else
  495.                 return (kbufp[n] & 0xFF);
  496. }
  497. fp = NULL;
  498.                 kused = 0;
  499.                 ksize = 0;
  500.         }
  501. }
  502.  
  503.